/*
 * G3DMExporter.cpp
 *
 *  Created on: Jan 13, 2014
 *      Author: knuke
 */

#include "G3DMExporter.hpp"

#include <iostream>
#include <vector>

#include "BinaryStreamWriter.hpp"
#include "Material.hpp"
#include "MaterialGroup.hpp"
#include "Mesh.hpp"
#include "Model.hpp"
#include "Node.hpp"
#include "Triangle.hpp"
#include "Types.hpp"
#include "Converter.hpp"

using std::string;
using std::ofstream;
using std::cout;
using std::endl;

namespace gengine
{

  G3DMExporter::G3DMExporter()
  {
  }

  G3DMExporter::~G3DMExporter()
  {
  }

  void G3DMExporter::exportModel(Model* model, string out_file)
  {
    stream_.open(out_file, false);

    uint mat_cnt = model->materials_.size();
    stream_.writeInt(mat_cnt, 4);  // Material Count

    COUNTER_LOOP(mat_idx, 0, mat_cnt)
      writeMaterial(model->materials_[mat_idx]);

    uint mesh_cnt = model->meshes_.size();
    stream_.writeInt(mesh_cnt, 4);  // Mesh Count

    COUNTER_LOOP(mesh_idx, 0, mesh_cnt)
      writeMesh(model->meshes_[mesh_idx]);

    writeNode(model->root_node_);

    cout << "Scene exported successfully." << endl;

    stream_.flush();
  }

  void G3DMExporter::writeMaterial(Material* mat)
  {
    stream_.writeFloat(mat->alpha_);  // Alpha
    stream_.writeFloats(&(mat->ambient_[0]), 3);  // Ambient
    stream_.writeFloats(&(mat->diffuse_[0]), 3);  // Diffuse
  }

  void G3DMExporter::writeMesh(Mesh* mesh)
  {
    uint v_cnt = mesh->vertices_.size();
    uint idx_size = 1;
    uint tmp = v_cnt;
    while (tmp > 256)
    {
      tmp /= 256;
      idx_size++;
    }
    stream_.writeInt(idx_size, 4);  // Size of an vertex index

    stream_.writeInt(v_cnt, idx_size);  // Vertex Count

    COUNTER_LOOP(v_idx, 0, v_cnt)
      stream_.writeFloats(&(mesh->vertices_[v_idx][0]), 3);  // Vertex

    uint mat_grp_cnt = mesh->material_groups_.size();
    stream_.writeInt(mat_grp_cnt, 4);  // Material Group Count

    COUNTER_LOOP(mat_grp_idx, 0, mat_grp_cnt)
    {
      MaterialGroup* mat_grp = mesh->material_groups_[mat_grp_idx];

      stream_.writeInt(mat_grp->material_, 4);  // Material Index

      uint tri_cnt = mat_grp->triangles_.size();
      stream_.writeInt(tri_cnt, 4);  // Triangle Count
      COUNTER_LOOP(tri_idx, 0, tri_cnt)
      {
        Triangle* tri = mat_grp->triangles_[tri_idx];
        stream_.writeInts(&(tri->vertex_indices_[0]), idx_size, 3);  // Vertex Indices
      }

    }
  }

  void G3DMExporter::writeNode(Node* node)
  {
    uint mesh_cnt = node->meshes_.size();
    stream_.writeInt(mesh_cnt, 4); // Mesh Count

    COUNTER_LOOP(mesh_idx, 0, mesh_cnt)
      stream_.writeInt(node->meshes_[mesh_idx], 4);  // Mesh ID

    uint child_cnt = node->children_.size();
    stream_.writeInt(child_cnt, 4);  // Child Count

    COUNTER_LOOP(child_idx, 0, child_cnt)
      writeNode(node->children_[child_idx]);
  }

} /* namespace graphiclicious_converter */
